package view;

import android.content.ClipData;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.util.Log;
import android.view.DragEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;

public class DragZoomImageView extends ImageView {
    Matrix matrix = new Matrix();
    Matrix savedMatrix = new Matrix();

    /**
     * 初始状态
     */
    static final int NONE = 0;
    /**
     * 拖动
     */
    static final int DRAG = 1;
    /**
     * 缩放
     */
    static final int ZOOM = 2;

    /**
     * 当前模式
     */
    int mode = NONE;

    int index;

    /**
     * 存储float类型的x，y值，就是你点下的坐标的X和Y
     */
    PointF prev = new PointF();
    PointF mid = new PointF();
    float dist = 1f;

    public DragZoomImageView(Context context) {
        super(context);
        setupView();
    }

    public DragZoomImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setupView();
    }

    public void setupView() {
        this.setScaleType(ScaleType.MATRIX);
        this.setOnTouchListener(new ManipulationListener());
        this.setOnDragListener(new DragListener());
    }

    public void setImageBitmap(final Bitmap bm, Matrix matrix, int index) {
        this.matrix = matrix;
        super.setImageBitmap(bm);
        this.setImageMatrix(matrix);
        this.index = index;
    }

    /**
     * 限制最大最小缩放比例，自动居中
     */
    public void checkScaleAndPosition() {
        if (mode == ZOOM) {
            checkScale();
        } else if (mode == DRAG) {
            checkPosition();
        }
        DragZoomImageView.this.setImageMatrix(matrix);
    }

    private void checkScale() {
        RectF dstRect = new RectF();
        RectF srcRect = new RectF(this.getDrawable().getBounds());
        boolean successFlag = matrix.mapRect(dstRect, srcRect);
        float scale = dstRect.width() / srcRect.width();

        float maxScale = 2.0f;

        float expectationScale = getMeasuredWidth() / srcRect.width() > getMeasuredHeight() / srcRect.height() ?
                getMeasuredWidth() / srcRect.width() : getMeasuredHeight() / srcRect.height();

        if (scale > maxScale) {
            float tscale = maxScale / scale;
            matrix.postScale(tscale, tscale, mid.x, mid.y);
        } else if (scale < expectationScale) {
            matrix.setScale(expectationScale, expectationScale);

        }
        checkPosition();
    }

    private void checkPosition() {
        RectF dstRect = new RectF();
        RectF srcRect = new RectF(this.getDrawable().getBounds());
        boolean successFlag = matrix.mapRect(dstRect, srcRect);

        Log.i("matrix:", "result:" + successFlag);

        float dx = 0;
        if (dstRect.width() > this.getWidth()) {
            if (dstRect.left > 0) {
                dx = -dstRect.left;
            } else if (dstRect.left + dstRect.width() < this.getWidth()) {
                dx = this.getWidth() - (dstRect.left + dstRect.width());
            }
        } else {
            dx = (this.getWidth() - dstRect.width()) * 0.5f + 0.5f - dstRect.left;
        }

        float dy = 0;
        if (dstRect.height() > this.getHeight()) {
            if (dstRect.top > 0) {
                dy = -dstRect.top;
            } else if (dstRect.top + dstRect.height() < this.getHeight()) {
                dy = this.getHeight() - (dstRect.top + dstRect.height());
            }
        } else {
            dy = (this.getHeight() - dstRect.height()) * 0.5f + 0.5f - dstRect.top;
        }
        matrix.postTranslate(dx, dy);
    }


    /**
     * 两点的距离
     */
    private float spacing(MotionEvent event) {
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);
//        return FloatMath.sqrt(x * x + y * y);
        return 1.0f;

    }

    /**
     * 两点的中点
     */
    private void midPoint(PointF point, MotionEvent event) {
        float x = event.getX(0) + event.getX(1);
        float y = event.getY(0) + event.getY(1);
        point.set(x / 2, y / 2);
        //Log.i("mid point","=============x:"+x+"   y:"+y);
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    //    @Override
//    public void setImageBitmap(final Bitmap bm) {
//        matrix = new Matrix();
//        savedMatrix = new Matrix();
//
//        this.setImageMatrix( new Matrix());
//        super.setImageBitmap(bm);
//
//        if( this.getMeasuredHeight() ==0 && this.getMeasuredWidth() ==0) {
//            ViewTreeObserver vto = this.getViewTreeObserver();
//            vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
//                @Override
//                public void onGlobalLayout() {
//                    DragZoomImageView.this.getViewTreeObserver().removeGlobalOnLayoutListener(this);
//                    initMatrix(bm);
//                    Log.i("initmatrix", "===========================onGlobalLayout");
//                }
//            });
//        }else {
//            initMatrix(bm);
//        }
//    }
//
    private void initMatrix(Bitmap bm) {
        int viewHeight = getMeasuredHeight();
        int viewWidth = getMeasuredWidth();
        Matrix m = new Matrix();
        RectF drawableRect = new RectF(0, 0, bm.getWidth(), bm.getHeight());
        RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
        m.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.CENTER);
        float wscale = bm.getWidth() / (float) viewWidth;
        float hscale = bm.getHeight() / (float) viewHeight;
        float zoomScale = wscale > hscale ? wscale / hscale : hscale / wscale;
        m.postScale(zoomScale, zoomScale, viewWidth / 2, viewHeight / 2);

        matrix = m;
        setImageMatrix(m);
        invalidate();
    }


    class ManipulationListener implements OnTouchListener {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            //Log.i("ImageView","ImageView event value:"+(event.getAction() & MotionEvent.ACTION_MASK));
//            // todo 统计代码
//            AppStatisticsManager.getAppsStatisticsManager().onEvent(AppStatistics.IN_PREVIEW, "");
            switch (event.getAction() & MotionEvent.ACTION_MASK) {
                // 主点按下
                case MotionEvent.ACTION_DOWN:
                    savedMatrix.set(matrix);
                    prev.set(event.getX(), event.getY());
                    mode = DRAG;
                    //System.out.println("----event.getX() --" + event.getX() + "----event.getY() --" + event.getY());
                    break;
                // 副点按下
                case MotionEvent.ACTION_POINTER_DOWN:
                    dist = spacing(event);
                    // 如果连续两点距离大于10，则判定为多点模式
                    if (spacing(event) > 10f) {
                        savedMatrix.set(matrix);
                        midPoint(mid, event);
                        mode = ZOOM;
                    }
                    break;
                case MotionEvent.ACTION_UP: {
                    checkPosition();
                    break;
                }
                case MotionEvent.ACTION_CANCEL: {
                    break;
                }
                case MotionEvent.ACTION_POINTER_UP:
                    checkScale();
                    mode = NONE;
                    break;
                case MotionEvent.ACTION_MOVE:
                    //
                    DragZoomImageView.this.setScaleType(ScaleType.MATRIX);
                    DragZoomImageView.this.setImageMatrix(matrix);
                    if (mode == DRAG) {

                        if (event.getX() > 0 && event.getX() < getWidth() && event.getY() > 0 && event.getY() < getHeight()) {
                            matrix.set(savedMatrix);
                            // 平移
                            matrix.postTranslate(event.getX() - prev.x, event.getY() - prev.y);
                        } else {
                            DragShadowBuilder dsb = new DragShadowBuilder(DragZoomImageView.this);
                            ClipData clipData = ClipData.newPlainText("", "");
                            DragZoomImageView.this.startDrag(clipData, dsb, DragZoomImageView.this, 0);
                        }

                    } else if (mode == ZOOM) {
                        float newDist = spacing(event);
                        if (newDist > 10f) {
                            matrix.set(savedMatrix);
                            float tScale = newDist / dist;
                            matrix.postScale(tScale, tScale, mid.x, mid.y);
                        }
                    }
                    break;
            }
            DragZoomImageView.this.setImageMatrix(matrix);
            return true;
        }


    }

    class DragListener implements OnDragListener {

        boolean containsDragable = false;

        @Override
        public boolean onDrag(View v, DragEvent dragEvent) {
            //Log.i("fragment", "fragment "+v+" onDrag value:"+ dragEvent.getLocalState() +"" + (dragEvent.getAction() & MotionEvent.ACTION_MASK));

            View dragView = (View) dragEvent.getLocalState();
            if (dragView == v)
                return false;

            boolean retValue = true;

            switch (dragEvent.getAction()) {
                case DragEvent.ACTION_DRAG_STARTED:
                    break;
                case DragEvent.ACTION_DRAG_EXITED:
                    containsDragable = false;
                    break;
                case DragEvent.ACTION_DRAG_ENTERED:
                    containsDragable = true;
                    break;
                case DragEvent.ACTION_DRAG_ENDED:

                    if (containsDragable) {
                        DragZoomImageView srcImagView = (DragZoomImageView) dragView;
                        DragZoomImageView destImagView = (DragZoomImageView) v;

                        Bitmap srcImg = ((BitmapDrawable) srcImagView.getDrawable()).getBitmap();
                        int srcIndex = srcImagView.getIndex();
                        Bitmap destImg = ((BitmapDrawable) destImagView.getDrawable()).getBitmap();
                        int destIndex = destImagView.getIndex();

                        srcImagView.setImageBitmap(destImg);
                        srcImagView.initMatrix(destImg);
                        srcImagView.setIndex(destIndex);

                        destImagView.setImageBitmap(srcImg);
                        destImagView.initMatrix(srcImg);
                        destImagView.setIndex(srcIndex);

                        containsDragable = false;

                        return false;
                    } else {
                        //放弃对src重新更新
                        DragZoomImageView srcImagView = (DragZoomImageView) dragView;
                        srcImagView.checkScaleAndPosition();
                    }
                    break;
                case DragEvent.ACTION_DROP:

                    break;
            }

            return retValue;
        }
    }
}
